package net.scribblemedia.candle.data.pattern;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.encog.ml.data.market.loader.LoadedMarketData;
import org.joda.time.DateMidnight;

public class PatternWindowFactory {
	public Collection<PatternWindow> createPatternWindows(List<LoadedMarketData> marketData, int tailSizeDays, int noseDataSizeDays) {
		List<PatternWindow> patternWindows = new ArrayList<PatternWindow>();
		
		int count = 0;
		
		Map<String, List<LoadedMarketData>> splitMarketData = new HashMap<String, List<LoadedMarketData>>();
		
		for (LoadedMarketData marketDataItem : marketData) {
			String tickerSymbol = marketDataItem.getTicker().getSymbol();
			
			if (splitMarketData.get(tickerSymbol) == null) {
				splitMarketData.put(tickerSymbol, new ArrayList<LoadedMarketData>());
			}
			
			splitMarketData.get(tickerSymbol).add(marketDataItem);
		}
		
		for (List<LoadedMarketData> marketDataForSingleStock : splitMarketData.values()) {
			for (LoadedMarketData marketDataItem : marketDataForSingleStock) {
				if (count + tailSizeDays + noseDataSizeDays > marketData.size()) {
					break;
				}
				
				DateMidnight patternWindowStartDate = new DateMidnight(marketDataItem.getWhen());
				PatternWindow patternWindow = new PatternWindow(marketDataItem.getTicker().getSymbol(), buildTailData(marketDataForSingleStock, patternWindowStartDate, tailSizeDays), buildNoseData(marketDataForSingleStock, patternWindowStartDate, noseDataSizeDays, tailSizeDays));
				patternWindows.add(patternWindow);
				count++;
			}
		}
		
		return patternWindows;
	}

	private Collection<LoadedMarketData> buildNoseData(Collection<LoadedMarketData> marketData, DateMidnight patternWindowStartDate, int noseDataSizeDays, int tailSizeDays) {
		Collection<LoadedMarketData> noseData = new ArrayList<LoadedMarketData>();
		for (LoadedMarketData marketDataItem : marketData) {
			if ((new DateMidnight(marketDataItem.getWhen()).isEqual(patternWindowStartDate.plusDays(tailSizeDays)) || 
					new DateMidnight(marketDataItem.getWhen()).isAfter(patternWindowStartDate.plusDays(tailSizeDays))) &&
					new DateMidnight(marketDataItem.getWhen()).isBefore(endOfPatternWindowDate(patternWindowStartDate, noseDataSizeDays, tailSizeDays))) {
				noseData.add(marketDataItem);
			}
		}
		return noseData;
	}

	private DateMidnight endOfPatternWindowDate(DateMidnight patternWindowStartDate, int noseDataSizeDays, int tailSizeDays) {
		return patternWindowStartDate.plusDays(noseDataSizeDays).plusDays(tailSizeDays);
	}

	private Collection<LoadedMarketData> buildTailData(Collection<LoadedMarketData> marketData, DateMidnight patternWindowStartDate, int tailSizeDays) {
		Collection<LoadedMarketData> tailData = new ArrayList<LoadedMarketData>();
		for (LoadedMarketData marketDataItem : marketData) {
			if ((new DateMidnight(marketDataItem.getWhen()).isEqual(patternWindowStartDate) || 
					new DateMidnight(marketDataItem.getWhen()).isAfter(patternWindowStartDate)) &&
					(new DateMidnight(marketDataItem.getWhen()).isBefore(patternWindowStartDate.plusDays(tailSizeDays - 1)) ||
					new DateMidnight(marketDataItem.getWhen()).isEqual(patternWindowStartDate.plusDays(tailSizeDays - 1)))) {
				tailData.add(marketDataItem);
			}
		}
		return tailData;
	}
}
